/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.femto.compmod.vis;

import java.sql.SQLException;

import java.awt.Font;
import java.awt.geom.*;

import javax.media.opengl.*;
import javax.media.opengl.glu.*;

import com.sun.opengl.util.*;
import com.sun.opengl.util.j2d.*;

import java.awt.event.MouseEvent;

import org.femto.compmod.OptionsDatabase;

import org.femto.math.linalg.*;
import org.femto.math.vis.*;

/**
 *
 * @author root
 */
public class VisualizerViewport implements GLEventListener, WorldRenderer {

    private int widthPixels;
    private int heightPixels;

    private Matrix4x4 projection = new Matrix4x4();

    private double fovY;
    private double nearZ;
    private double farZ;
    
    private Vec3 backgroundColor1;
    private Vec3 backgroundColor2;

    private Camera camera = new Camera(this);

    private GLUT glut;
    private GLU glu;

    private TextRenderer textRendererSmall;

    public VisualizerViewport() throws SQLException, IllegalArgumentException {
        backgroundColor1 = OptionsDatabase.loadOptionFloat3("vis.backgroundColor1");
        backgroundColor2 = OptionsDatabase.loadOptionFloat3("vis.backgroundColor2");
        fovY = OptionsDatabase.loadOptionFloat("vis.fovY");
        nearZ = OptionsDatabase.loadOptionFloat("vis.nearZ");
        farZ = OptionsDatabase.loadOptionFloat("vis.farZ");
        camera.setWorldRenderer(this);
        textRendererSmall = new TextRenderer(new Font("Arial", Font.PLAIN, 18));
    }

    public Camera getCamera() {
        return camera;
    }

    public void init(GLAutoDrawable drawable) {
        widthPixels = drawable.getWidth();
        heightPixels = drawable.getHeight();

        GL gl = drawable.getGL();
        glut = new GLUT();
        glu = new GLU();

        camera.prepare(gl);
        //initLight(gl);
    }

    private void drawBackground(GL gl) {
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glPushMatrix();
        gl.glLoadIdentity();

        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();

        gl.glDisable(GL.GL_LIGHTING);
        gl.glDisable(GL.GL_DEPTH_TEST);

        gl.glBegin(GL.GL_QUADS);
        gl.glColor3dv(backgroundColor1.toArray(), 0);
        gl.glVertex2d(-1.0, -1.0);
        gl.glVertex2d(1.0, -1.0);
        gl.glColor3dv(backgroundColor2.toArray(), 0);
        gl.glVertex2d(1.0, 1.0);
        gl.glVertex2d(-1.0, 1.0);
        gl.glEnd();

        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glPopMatrix();

        gl.glClear(GL.GL_DEPTH_BUFFER_BIT);
    }

    private void drawGizmos(GL gl) {
        gl.glColor3d(0.0, 0.0, 0.0);

        gl.glBegin(GL.GL_LINE_LOOP);
        gl.glVertex2i(1, 0);
        gl.glVertex2i(widthPixels, 0);
        gl.glVertex2i(widthPixels, heightPixels-1);
        gl.glVertex2i(1, heightPixels-1);
        gl.glEnd();

        /*
        if(manipulator.getStateName().equals("TRACKBALL")) {
            drawCircle(gl, 0.5*widthPixels, 0.5*heightPixels, 0.5*Math.min(widthPixels, heightPixels), 80);
            drawCircle(gl, 0.5*widthPixels, 0.5*heightPixels, 0.5*Math.max(widthPixels, heightPixels), 90);
        }*/
    }

    private void drawGUI(GL gl) {
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glPushMatrix();
        gl.glLoadIdentity();
        glu.gluOrtho2D(0.0, (double) widthPixels, 0.0, (double) heightPixels);

        textRendererSmall.beginRendering(widthPixels, heightPixels);

        Rectangle2D bounds = textRendererSmall.getBounds("Perspective Anaglyph");

        textRendererSmall.draw("Perspective Anaglyph", 10, heightPixels-(int)bounds.getHeight());

        textRendererSmall.endRendering();


        gl.glPopMatrix();
    }

    public void display(GLAutoDrawable drawable) {
        GL gl = drawable.getGL();

        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

        drawBackground(gl);

        /*
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glPushMatrix();
        gl.glLoadMatrixd(projection.m, 0);
        gl.glMultMatrixd(manips.getTransform().m, 0);
        gl.glMultMatrixd(camera.getTransform().m, 0);

        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glPushMatrix();
        gl.glLoadIdentity();
        

        gl.glColor3d(1.0, 1.0, 1.0);
        glut.glutWireTeapot(0.8, false);
        gl.glPopMatrix();

        gl.glPopMatrix();

i
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glPushMatrix();

         */

        //camera.setView(manips.getTransform());
        //camera.setCenterAndEye(new Vec3(0,0,4), new Vec3(10, 10, 10));
        camera.render(gl);


        Matrix4x4 projGUI = new Matrix4x4();
        projGUI.setOrthographicStandardAnamorphic(widthPixels, heightPixels, nearZ, farZ);

        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glPushMatrix();
        gl.glLoadMatrixd(projGUI.m, 0);
        camera.renderManipulators(gl);
        gl.glPopMatrix();
        
        Matrix4x4 projPixelsGUI = new Matrix4x4();
        projPixelsGUI.setOrthographic(0, widthPixels, 0, heightPixels, -1, 1);
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glPushMatrix();
        gl.glLoadMatrixd(projPixelsGUI.m, 0);
        camera.drawGUI(gl);
        gl.glPopMatrix();

        //drawGUI(gl);

        gl.glFlush();
        
        //drawable.swapBuffers();
    }

    public void render(GL gl) {


        gl.glEnable(GL.GL_DEPTH_TEST);
        //glut.glutSolidTeapot(5, false);
        glut.glutWireTeapot(0.5, false);
    }

    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
    }

    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
        widthPixels = width;
        heightPixels = height;

        camera.reshape(width, height);

        GL gl = drawable.getGL();

        gl.glViewport(0, 0, width, height);
    }

    private void drawGroundGrid(GL gl, int n, int m) {
        gl.glBegin(GL.GL_LINES);
        for(int i = 0; i < n+1; i++)
        {
                gl.glVertex2d((double)i/(double)n, 0);
                gl.glVertex2d((double)i/(double)n, 1);
        }
        for(int j = 0; j < m+1; j++)
        {
                gl.glVertex2d(0, (double)j/(double)m);
                gl.glVertex2d(1, (double)j/(double)m);
        }
        gl.glEnd();
    }

    private void initLight(GL gl) {
        float ambient[] = { 0.4f, 0.4f, 0.4f, 1.0f };
        float diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
        float specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
        float position[] = { 10.0f, 10.0f, 10.0f, 0.0f };
        float mat_ambient[] = { 0.2f, 0.2f, 0.2f, 1.0f };
        float mat_diffuse[] = { 0.7f, 0.7f, 0.7f, 1.0f };
        float mat_specular[] = { 0.9f, 0.9f, 0.9f, 1.0f };
        float mat_shininess[] = { 50.0f };
        float lmodel_ambient[] = { 0.2f, 0.2f, 0.2f, 1.0f };

        gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, ambient, 0);
        gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, diffuse, 0);
        gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, specular, 0);
        gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, position, 0);

        gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, mat_ambient, 0);
        gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, mat_diffuse, 0);
        gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, mat_specular, 0);
        gl.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, mat_shininess, 0);

        gl.glLightModelfv(GL.GL_LIGHT_MODEL_AMBIENT, lmodel_ambient, 0);

        gl.glEnable(GL.GL_LIGHT0);
        gl.glEnable(GL.GL_AUTO_NORMAL);
        gl.glEnable(GL.GL_NORMALIZE);

        gl.glEnable(GL.GL_CULL_FACE);
        gl.glCullFace(GL.GL_FRONT);
    }


}
